10 中间件
在前面的文章中,我们学会了创建Agent、定义工具、管理记忆、流式输出等等。但在实际项目中,你经常会遇到一些"横切关注点"的问题——比如:
- 每次模型调用前都要记日志
- 工具调用失败时要自动重试
- 对话太长时要自动摘要
- 涉及敏感操作时要人工确认
- 输出中包含个人信息时要脱敏
这些功能如果写在业务代码里,会很乱很杂。中间件就是来解决这类问题的——它让你在Agent执行的各个关键节点插入自定义逻辑,而不用改动核心代码。
一、什么是中间件
中间件(Middleware)是一种拦截器机制,可以在Agent执行的特定时机插入自定义逻辑。打个比方,如果Agent的执行流程是一条流水线,中间件就像是流水线上的"检查站",你可以在每个检查站做日志记录、数据校验、格式转换等操作。
中间件最常见的用途:
- 日志和调试:记录Agent的输入输出,方便排查问题
- 提示词转换:动态修改系统提示词,注入用户上下文
- 工具选择:根据场景动态选择可用工具
- 重试和回退:模型调用失败时自动重试或切换备用模型
- 安全防护:PII脱敏、内容审核、速率限制
- 人机交互:敏感操作需要人工确认
二、添加中间件
使用create_agent的middleware参数传入中间件列表:
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware, HumanInTheLoopMiddleware
agent = create_agent(
model="deepseek-v4-flash",
tools=[...],
middleware=[
SummarizationMiddleware(...),
HumanInTheLoopMiddleware(...),
],
)中间件按照列表顺序执行,排在前面的先执行。
三、内置中间件
LangChain提供了一系列开箱即用的内置中间件,覆盖了最常见的场景。
3.1 消息摘要(SummarizationMiddleware)
当对话越来越长时,token消耗会急剧增加。摘要中间件可以在对话超过一定长度时自动压缩历史消息,保留关键信息的同时减少token占用。
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
agent = create_agent(
model="deepseek-v4-flash",
tools=[...],
middleware=[
SummarizationMiddleware(
max_tokens=4000, # 对话超过4000 token时触发摘要
),
],
)3.2 人机交互(HumanInTheLoopMiddleware)
有些操作比较敏感,比如发邮件、删除数据、修改配置等,你希望在执行前让人工确认一下。人机交互中间件可以在指定工具调用前暂停,等待用户确认后再继续。
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
agent = create_agent(
model="deepseek-v4-flash",
tools=[send_email, delete_file],
middleware=[
HumanInTheLoopMiddleware(
interrupt_on={
"send_email": True, # 调用send_email前暂停
"delete_file": True, # 调用delete_file前暂停
}
),
],
)当Agent要调用这些工具时,会暂停执行并返回一个中断信息,用户确认后再用Command恢复执行。
3.3 PII脱敏(PIIMiddleware)
如果Agent的输出可能包含用户的个人信息(邮箱、电话、身份证号等),可以用PII中间件自动检测并脱敏。
from langchain.agents import create_agent
from langchain.agents.middleware import PIIMiddleware
agent = create_agent(
model="deepseek-v4-flash",
tools=[...],
middleware=[
PIIMiddleware(
"email", # 脱敏邮箱
strategy="redact", # 策略:替换为[REDACTED]
),
],
)支持的PII类型:email、phone、credit_card、ssn(美国社会安全号)等。
3.4 工具重试(ToolRetryMiddleware)
工具调用有时候会因为网络问题、超时等原因失败。重试中间件可以自动重试失败的工具调用。
from langchain.agents import create_agent
from langchain.agents.middleware import ToolRetryMiddleware
agent = create_agent(
model="deepseek-v4-flash",
tools=[call_api],
middleware=[
ToolRetryMiddleware(
max_retries=3, # 最多重试3次
retry_delay=1.0, # 每次重试间隔1秒
),
],
)3.5 模型回退(ModelFallbackMiddleware)
当主模型不可用时(比如API超时、限流),自动切换到备用模型,保证服务不中断。
from langchain.agents import create_agent
from langchain.agents.middleware import ModelFallbackMiddleware
agent = create_agent(
model="deepseek-v4-flash",
tools=[...],
middleware=[
ModelFallbackMiddleware(
fallback_models=["openai:gpt-5.4", "anthropic:claude-sonnet-4-6"],
),
],
)3.6 调用次数限制(ModelCallLimitMiddleware)
防止Agent陷入死循环,限制模型调用的最大次数。
from langchain.agents import create_agent
from langchain.agents.middleware import ModelCallLimitMiddleware
agent = create_agent(
model="deepseek-v4-flash",
tools=[...],
middleware=[
ModelCallLimitMiddleware(max_calls=10), # 最多调用10次模型
],
)3.7 LLM工具选择(LLMToolSelectorMiddleware)
当工具很多时,把所有工具都传给模型会浪费token,也可能影响工具选择的准确性。这个中间件可以让LLM根据用户的问题,动态选择最相关的工具子集。
from langchain.agents import create_agent
from langchain.agents.middleware import LLMToolSelectorMiddleware
agent = create_agent(
model="deepseek-v4-flash",
tools=[...], # 注册所有工具
middleware=[
LLMToolSelectorMiddleware(
max_tools=5, # 每次最多选择5个工具
),
],
)四、中间件的执行顺序
当中间件有多个时,它们的执行顺序是有讲究的:
before类Hook(before_agent、before_model):按列表顺序从前往后执行
after类Hook(after_model、after_agent):按列表顺序从后往前执行(反序)
wrap类Hook(wrap_model_call、wrap_tool_call):像洋葱一样层层嵌套
举个例子:
agent = create_agent(
model="deepseek-v4-flash",
middleware=[middleware1, middleware2, middleware3],
tools=[...],
)执行顺序:
middleware1.before_agent()
middleware2.before_agent()
middleware3.before_agent()
Agent循环开始:
middleware1.before_model()
middleware2.before_model()
middleware3.before_model()
middleware1.wrap_model_call() →
middleware2.wrap_model_call() →
middleware3.wrap_model_call() → 调用模型
middleware3.after_model()
middleware2.after_model()
middleware1.after_model()
Agent循环结束
middleware3.after_agent()
middleware2.after_agent()
middleware1.after_agent()简单记:before从前往后,after从后往前,wrap像洋葱一样嵌套。
五、在LangGraph工作流中使用中间件
中间件不是独立的运行时,它运行在create_agent返回的LangGraph图内部。你可以把带中间件的Agent作为节点嵌入到更大的LangGraph工作流中:
from langchain.agents import create_agent, AgentState
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.graph import START, StateGraph
# 创建带中间件的Agent
email_agent = create_agent(
model="deepseek-v4-flash",
tools=[read_email, send_email],
middleware=[HumanInTheLoopMiddleware(interrupt_on={"send_email": True})],
)
# 把Agent作为节点嵌入到更大的工作流中
graph = (
StateGraph(AgentState)
.add_node("classify", classify_node)
.add_node("email_agent", email_agent)
.add_edge(START, "classify")
.add_conditional_edges("classify", route)
.compile()
)中间件的所有功能(人机交互、摘要、PII脱敏等)都会跟着Agent节点一起工作。
六、总结
中间件是LangChain中扩展Agent能力的核心机制:
- 中间件可以在Agent执行的各个关键节点插入自定义逻辑
- 内置中间件覆盖了最常见的场景:摘要、人机交互、PII脱敏、重试、回退、调用限制、工具选择
- 通过
create_agent的middleware参数添加,支持多个中间件组合使用 - 执行顺序:before从前往后,after从后往前,wrap嵌套
在下一篇文章中,我们将学习如何编写自定义中间件,实现更灵活的Agent控制逻辑。